////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef xmlreader_h__
#define xmlreader_h__

#include "iosystem/streamreader.h"
#include "math/float2.h"
#include "math/float4.h"
#include "math/matrix.h"
#include "ticpp/ticpp.h"

namespace IO
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	XmlReader
	///
	/// \brief	Xml reader. 
	///
	/// \author	khaos
	/// \date	12.01.2010
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class XmlReader : public StreamReader
	{
		RE_DeclareClass(IO::XmlReader);

	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	XmlReader()
		///
		/// \brief	Default constructor. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		XmlReader();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual ~XmlReader()
		///
		/// \brief	Finaliser. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~XmlReader();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool Open()
		///
		/// \brief	Opens the xml stream.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	True if it was successfully opened, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool Open();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Close()
		///
		/// \brief	Closes the xml stream.
		///
		/// \author	Markus
		/// \date	13.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Close();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool HasNode(const Helper::String & path) const
		///
		/// \brief	Determines if this path has a Node.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	path	Full Node path. 
		///
		/// \return	True if there is a Node, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool HasNode(const Helper::String & path) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::String GetCurrentNodeName() const
		///
		/// \brief	Gets the current node name. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	The current node name. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::String GetCurrentNodeName() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::String GetCurrentNodePath() const
		///
		/// \brief	Gets the current node path. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	The current node path. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::String GetCurrentNodePath() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	tSize GetCurrentNodeLineNumber() const
		///
		/// \brief	Gets the current node line number. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	The current node line number. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		tSize GetCurrentNodeLineNumber() const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetNode(const Helper::String & path)
		///
		/// \brief	Sets a node. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	path	Name of the Node. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetNode(const Helper::String & path);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool SetFirstChild(const Helper::String & name)
		///
		/// \brief	Sets the first child Node found within the Node.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	name	The name of the parent Node. 
		///
		/// \return	True if the Node has at least one child, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool SetFirstChild(const Helper::String & name);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool SetNextChild(const Helper::String & name)
		///
		/// \brief	Goes on to the next child and returns if there was one.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	name	The name of the next child Node. 
		///
		/// \return	True if there was a next child Node, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool SetNextChild(const Helper::String & name);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool SetParent()
		///
		/// \brief	Determines if this Node has a parent Node. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	True if this has a parent, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool SetParent();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool HassAttr(const Helper::String & attr) const
		///
		/// \brief	Determines if this Node hast attributes.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The attribute. 
		///
		/// \return	True if Nodes are available, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool HassAttr(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::Array<Helper::String> GetAttrs() const
		///
		/// \brief	Returns an Array containing all attributes of the Node.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	An Array containing all attributes of the Node.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::Array<Helper::String> GetAttrs() const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool HasContent() const
		///
		/// \brief	Determines if this node has text content.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	True if this Node has content, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool HasContent() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::String GetContent() const
		///
		/// \brief	Returns the content. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \return	The content. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::String GetContent() const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::String GetString( const Helper::String & attr) const
		///
		/// \brief	Returns the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The String we are trying to read. 
		///
		/// \return	The string. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::String GetString( const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool GetBool(const Helper::String & attr) const
		///
		/// \brief	Returns the bool specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The bool we are trying to read. 
		///
		/// \return	The bool.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool GetBool(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	int GetInt(const Helper::String & attr) const
		///
		/// \brief	Returns the int specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The int we are trying to read. 
		///
		/// \return	The int. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		int GetInt(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	float GetFloat(const Helper::String & attr) const
		///
		/// \brief	Returns the float specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float we are trying to read.
		///
		/// \return	The float. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		float GetFloat(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::float2 GetFloat2(const Helper::String & attr) const
		///
		/// \brief	Returns the float2 specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float2 we are trying to read. 
		///
		/// \return	The float2. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::float2 GetFloat2(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::float4 GetFloat4(const Helper::String & attr) const
		///
		/// \brief	Returns the float4 specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float4 we are trying to read. 
		///
		/// \return	The float4.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::float4 GetFloat4(const Helper::String & attr) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::matrix GetMatrix(const Helper::String & attr) const
		///
		/// \brief	Returns the matrix44 specified through the String.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The matrix44 we are trying to read. 
		///
		/// \return	The matrix. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::matrix GetMatrix(const Helper::String & attr) const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Helper::String GetOptionalString( const Helper::String & attr,
		/// 	const Helper::String & val) const
		///
		/// \brief	If a String is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The String we are trying to read. 
		/// \param	[in]	val		The String we will use instead. 
		///
		/// \return	The String.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Helper::String GetOptionalString( const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool GetOptionalBool(const Helper::String & attr, const Helper::String & val) const
		///
		/// \brief	If a bool is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The bool we are trying to read. 
		/// \param	[in]	val		The bool we will use instead. 
		///
		/// \return	The bool.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool GetOptionalBool(const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	int GetOptionalInt(const Helper::String & attr, const Helper::String & val) const
		///
		/// \brief	If a int is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The int we are trying to read. 
		/// \param	[in]	val		The int we will use instead. 
		///
		/// \return	The int. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		int GetOptionalInt(const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	float GetOptionalFloat(const Helper::String & attr, const Helper::String & val) const
		///
		/// \brief	If a float is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float we are trying to read. 
		/// \param	[in]	val		The float we will use instead. 
		///
		/// \return	The float. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		float GetOptionalFloat(const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::float2 GetOptionalFloat2(const Helper::String & attr,
		/// 	const Helper::String & val) const
		///
		/// \brief	If a float2 is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float2 we are trying to read. 
		/// \param	[in]	val		The float2 we will use instead. 
		///
		/// \return	The float2. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::float2 GetOptionalFloat2(const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::float4 GetOptionalFloat4(const Helper::String & attr,
		/// 	const Helper::String & val) const
		///
		/// \brief	If a float4 is found this one will be returned, otherwise the
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The float4 we are trying to read. 
		/// \param	[in]	val		The float4 we will use instead. 
		///
		/// \return	The float4. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::float4 GetOptionalFloat4(const Helper::String & attr, const Helper::String & val) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Math::matrix GetOptionalMatrix(const Helper::String & attr,
		/// 	const Helper::String & val) const
		///
		/// \brief	If a matrix44 is found this one will be returned, otherwise the 
		///			alternative one specified through the String will be returned.
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	attr	The matrix44 we are trying to read. 
		/// \param	[in]	val		The matrix44 we will use instead. 
		///
		/// \return	A matrix.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Math::matrix GetOptionalMatrix(const Helper::String & attr, const Helper::String & val) const;

	protected:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	ticpp::Node * FindNode(const Helper::String & path) const
		///
		/// \brief	Searches for the first node. 
		///
		/// \author	Markus
		/// \date	13.02.2010
		///
		/// \param	[in]	path	Full pathname of the file. 
		///
		/// \return	null if it fails, else the found node. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		ticpp::Node * FindNode(const Helper::String & path) const;

	private:

		ticpp::Document *		m_xmlDoc;
		ticpp::Element *		m_curNode;

	};

}

#endif // xmlreader_h__